﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using Android.App;
using Android.Content;
using Android.Widget;
using LinkNote.Core;
using LinkNote.Model;
using Newtonsoft.Json;

namespace LinkNote
{
    public class HttpClient : WebClient
    {
        // Cookie 容器
        private CookieContainer cookieContainer;

        /// <summary>
        /// 创建一个新的 WebClient 实例。
        /// </summary>
        public HttpClient()
        {
            this.cookieContainer = new CookieContainer();
        }

        /// <summary>
        /// 创建一个新的 WebClient 实例。
        /// </summary>
        /// <param name="cookie">Cookie 容器</param>
        public HttpClient(CookieContainer cookies)
        {
            this.cookieContainer = cookies;
        }

        /// <summary>
        /// Cookie 容器
        /// </summary>
        public CookieContainer Cookies
        {
            get { return this.cookieContainer; }
            set { this.cookieContainer = value; }
        }

        /// <summary>
        /// 返回带有 Cookie 的 HttpWebRequest。
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        protected override WebRequest GetWebRequest(Uri address)
        {
            WebRequest request = base.GetWebRequest(address);
            if (request is HttpWebRequest)
            {
                HttpWebRequest httpRequest = request as HttpWebRequest;
                httpRequest.CookieContainer = cookieContainer;
            }
            return request;
        }
    }

    public class WebQuery
    {
        public delegate void QueryResultDelegate<in T>(QueryResult result, T data);
        public delegate void QueryResultDelegate(QueryResult result);

        public static CookieContainer cookie = new CookieContainer();
        public const string server = "http://demo.linkapp.com.cn";

        static private ProgressDialog _progressDialog;
        private static Activity context;

        static public void Init(Activity con)
        {
            context = con;
            _progressDialog = new ProgressDialog(context) { Indeterminate = true };            
        }

        static public void ShowProgress(string title, string msg)
        {
            if (_progressDialog != null && context !=null)
            {
                _progressDialog.SetTitle(title);
                _progressDialog.SetMessage(msg);
                _progressDialog.Show();
            }
        }

        public static void HideProgress()
        {
            if (_progressDialog != null && context !=null)
                _progressDialog.Hide();
        }

        private static void RemoteDownloadOperate(string url, QueryResultDelegate callback)
        {
            var wc = new HttpClient(cookie) { Encoding = Encoding.UTF8 };
            wc.DownloadStringAsync(new Uri(url));

            wc.DownloadStringCompleted += delegate(object sender, DownloadStringCompletedEventArgs e)
                {
                    var result = "";
                    try
                    {
                        result = e.Result;
                        Console.WriteLine(result);
                        var rr = JsonConvert.DeserializeObject<QueryResult>(result);
                        if (callback != null)
                        {
                            if (context == null)
                                callback(rr);
                            else
                                context.RunOnUiThread(() =>
                                    {
                                        HideProgress();
                                        callback(rr);
                                    });
                        }
                    }
                    catch (Exception exception)
                    {
                        context.RunOnUiThread(() =>
                            {
                                HideProgress();
                                Toast.MakeText(context, "网络操作异常："+exception.Message, ToastLength.Long);                         
                            });
                        Console.WriteLine(result);
                    }
                };
        }

        private static void RemoteUploadOperate(string url, NameValueCollection values, QueryResultDelegate callback)
        {
            var wc = new HttpClient(cookie) { Encoding = Encoding.UTF8 };
            wc.UploadValuesAsync(new Uri(url), values);

            wc.UploadValuesCompleted += delegate(object sender, UploadValuesCompletedEventArgs e)
            {
                var result = "";
                try
                {
                    result = Encoding.UTF8.GetString(e.Result);
                    Console.WriteLine(result);
                    var rr = JsonConvert.DeserializeObject<QueryResult>(result);
                    if (callback != null)
                    {
                        if (context == null)
                            callback(rr);
                        else
                            context.RunOnUiThread(() =>
                            {
                                HideProgress();
                                callback(rr);
                            });
                    }
                }
                catch (Exception exception)
                {
                    context.RunOnUiThread(() =>
                    {
                        HideProgress();
                        Toast.MakeText(context, "网络操作异常：" + exception.Message, ToastLength.Long);
                    });
                    Console.WriteLine(result);
                }
            };
        }

        private static void RemoteDownloadOperate<T>(string url, QueryResultDelegate<T> callback)
        {
            var wc = new HttpClient(cookie) { Encoding = Encoding.UTF8 };
            wc.DownloadStringAsync(new Uri(url));

            wc.DownloadStringCompleted += delegate(object sender, DownloadStringCompletedEventArgs e)
                {
                    try
                    {
                        string result = e.Result;
                        Console.WriteLine(result);
                        CallBack<T>(result, callback);
                    }
                    catch (Exception exception)
                    {
                        context.RunOnUiThread(() =>
                        {
                            HideProgress();
                            Toast.MakeText(context, "网络操作异常：" + exception.Message, ToastLength.Long);
                        });
                        Console.WriteLine(exception);
                    }
                };
        }

        private static void RemoteUploadOperate<T>(string url, NameValueCollection data, QueryResultDelegate<T> callback)
        {
            var wc = new HttpClient(cookie) { Encoding = Encoding.UTF8 };
            wc.UploadValuesAsync(new Uri(url), data);

            wc.UploadValuesCompleted += delegate(object sender, UploadValuesCompletedEventArgs e)
                {
                    try
                    {
                        string result = Encoding.UTF8.GetString(e.Result);
                        Console.WriteLine(result);
                        CallBack<T>(result, callback);
                    }
                    catch (Exception exception)
                    {
                        context.RunOnUiThread(() =>
                        {
                            HideProgress();
                            Toast.MakeText(context, "网络操作异常：" + exception.Message, ToastLength.Long);
                        });
                        Console.WriteLine(exception);
                    }
                };
        }

        private static void CallBack<T>(string result, QueryResultDelegate<T> callback)
        {
            QueryResult rr = null;
            if(!string.IsNullOrEmpty(result))
                rr = JsonConvert.DeserializeObject<QueryResult>(result);
            if (callback != null)
            {
                var lr = JsonConvert.DeserializeObject<T>(result);
                if (context == null)
                    callback(rr, lr);
                else
                    context.RunOnUiThread(() =>
                        {
                            HideProgress();
                            callback(rr, lr);
                        });
            }
        }

        static public void Login(string name, string pass, string tip, QueryResultDelegate<User> callback)
        {
            ShowProgress(tip, "请等待......");
            NameValueCollection values = new NameValueCollection();
            values.Add("username", name);
            values.Add("password", pass);
            RemoteUploadOperate<User>(string.Format("{0}/apiLogin.action", server), values, callback);
        }

        static public void SaveNote(int noteid, string vision, string notetitle, string description, string noteContent, int noteCatalogueId, string author, string source, string tags, string tip, QueryResultDelegate<SaveNoteResult> callback)
        {
            string url = string.Format("{0}/note/noteAddNoteBook.action", server);
            ShowProgress(tip, "请等待......");
            NameValueCollection values = new NameValueCollection();
            if(noteid>0)
                values.Add("noteid", noteid.ToString());
            values.Add("vision", vision ?? string.Empty);
            values.Add("notetitle", notetitle ?? string.Empty);
            values.Add("description", description ?? string.Empty);
            values.Add("noteContent", noteContent ?? string.Empty);
            values.Add("noteCatalogueId", noteCatalogueId.ToString());
            values.Add("author", author ?? string.Empty);
            values.Add("source", source ?? string.Empty);
            values.Add("tags", tags ?? string.Empty);
            RemoteUploadOperate<SaveNoteResult>(url, values, callback);
        }

        public static void AddAttachment(int noteid, int attachid, string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteAddAttachment.action?noteid={1}&attachmentIds={2}", server, noteid, attachid);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate(url, callback);
        }

        public static void DelAttachment(int noteid, int attachid, string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteDelAttachment.action?noteid={1}&attachmentIds={2}", server, noteid, attachid);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate(url, callback);
        }

        static public void DeleteNote(int noteid, int notestatus, int notecatalogueid, string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteDeleteNoteBook.action?noteid={1}&notestatus={2}& notecatalogueid={3}", server, noteid, notestatus, notecatalogueid);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate(url, callback);        
        }

        static public void AddDir(string name, string tip, QueryResultDelegate<AddDirResult> callback)
        {
            string url = string.Format("{0}/note/noteAddDir.action", server);
            ShowProgress(tip, "请等待......");
            NameValueCollection values = new NameValueCollection();
            values.Add("data", name);
            RemoteUploadOperate<AddDirResult>(url, values, callback);
        }

        static public void DeleteDir(int id, string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteDeleteDir.action?data={1}", server, id);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate(url, callback);
        }

        static public void UpdateDir(int id, string name, string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteUpdateDir.action", server);
            ShowProgress(tip, "请等待......");
            NameValueCollection values = new NameValueCollection();
            values.Add("data", id.ToString());
            values.Add("rename", name);
            RemoteUploadOperate(url, values, callback);         
        }

        static public void UpdateNoteDir(int id, int oldcata, int newcata, string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteUpdateNoteBook.action?noteid={1}&notecatalogueid={2}&newNotecatalogueid={3}", server, id, oldcata, newcata);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate(url, callback);         
        }

        static public void FindNoteById(int id, string tip, QueryResultDelegate<FindNoteBookResult> callback)
        {
            string url = string.Format("{0}/note/noteFindById.action?id={1}", server, id);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate<FindNoteBookResult>(url, callback);       
        }

        static public void FindNoteContentById(int id, string tip, QueryResultDelegate<FindNoteContentResult> callback)
        {
            string url = string.Format("{0}/note/noteFindNoteContent.action?noteid={1}", server, id);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate<FindNoteContentResult>(url, callback);        
        }

        static public void GetGarbageNote(string tip, QueryResultDelegate<FindNoteBookResult> callback)
        {
            string url = string.Format("{0}/note/noteGetGarbage.action", server);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate<FindNoteBookResult>(url, callback);       
        }

        static public void FindNoteBookByDir(int notecatalogueid, int pageNo, string tip, QueryResultDelegate<FindNoteBookResult> callback)
        {
            string url = string.Format("{0}/note/noteFindNoteBookByDir.action?notecatalogueid={1}&pageNo={2}", server, notecatalogueid, pageNo);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate<FindNoteBookResult>(url, callback);       
        }

        static public void UpdateDefaultDir(int id, int oldid, string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteRefreshDefault.action?id={1}&oldid={2}", server, id, oldid);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate(url, callback);       
        }

        static public void ClearGarbage(string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteClearGarbage.action", server);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate(url, callback);        
        }

        static public void InitDir(string tip, QueryResultDelegate<InitDirResult> callback)
        {
            string url = string.Format("{0}/note/noteInitDir.action", server);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate<InitDirResult>(url, callback);        
        }

        static public void noteRestore(int noteid, string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteRestore.action?noteid={1}", server, noteid);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate(url, callback);        
        }

        static public void noteGetAttachmentList(int noteid, string tip, QueryResultDelegate callback)
        {
            string url = string.Format("{0}/note/noteGetAttachmentList.action?noteid={1}", server, noteid);
            ShowProgress(tip, "请等待......");
            RemoteDownloadOperate(url, callback);        
        }

        static public void FileUpload(string file, string tip, QueryResultDelegate<UploadResult> callback)
        {
            Uri uri = new Uri(string.Format("{0}/note/fileUploadApi.action", server));
            var wc = new HttpClient(cookie) { Encoding = Encoding.UTF8 };
            ShowProgress(tip, "请等待......");
            wc.UploadFileAsync(uri, file);
            wc.UploadProgressChanged += delegate(object sender, UploadProgressChangedEventArgs args)
                {
                    context.RunOnUiThread(() =>
                        {
                            _progressDialog.IncrementProgressBy(args.ProgressPercentage);                            
                        });

                };
            wc.UploadFileCompleted += delegate(object sender, UploadFileCompletedEventArgs args)
                {
                    //HideProgress();
                    string result = Encoding.UTF8.GetString(args.Result);
                    CallBack(result, callback);
                };
        }

        /*
        private void Upload_Request(string address, string fileNamePath, string saveName)
        {
            // 要上传的文件
            FileStream fs = new FileStream(fileNamePath, FileMode.Open, FileAccess.Read);
            BinaryReader r = new BinaryReader(fs);
            //时间戳
            string strBoundary = "----------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--" + strBoundary + "\r\n");
            //请求头部信息
            StringBuilder sb = new StringBuilder();
            sb.Append("--");
            sb.Append(strBoundary);
            sb.Append("\r\n");
            sb.Append("Content-Disposition: form-data; name=\"");
            sb.Append("file");
            sb.Append("\"; filename=\"");
            sb.Append(saveName);
            sb.Append("\"");
            sb.Append("\r\n");
            sb.Append("Content-Type: ");
            sb.Append("application/octet-stream");
            sb.Append("\r\n");
            sb.Append("\r\n");

            string strPostHeader = sb.ToString();
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(strPostHeader);

            // 根据uri创建HttpWebRequest对象
            HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(new Uri(address));
            httpReq.Method = "POST";

            //对发送的数据不使用缓存【重要、关键】
            httpReq.AllowWriteStreamBuffering = false;

            //设置获得响应的超时时间（300秒）
            httpReq.Timeout = 300000;
            httpReq.ContentType = "multipart/form-data; boundary=" + strBoundary;
            long length = fs.Length + postHeaderBytes.Length + boundaryBytes.Length;
            long fileLength = fs.Length;
            httpReq.ContentLength = length;

            try
            {
                int bufferLength = 4096;
                byte[] buffer = new byte[bufferLength];

                //已上传的字节数
                long offset = 0;
                //开始上传时间
                DateTime startTime = DateTime.Now;
                int size = r.Read(buffer, 0, bufferLength);
                Stream postStream = httpReq.GetRequestStream();

                //发送请求头部消息
                postStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);
                while (size > 0)
                {
                    postStream.Write(buffer, 0, size);
                    offset += size;

                    //progressBar.Value = offset;//(int)(offset * (int.MaxValue / length));
                    TimeSpan span = DateTime.Now - startTime;
                    double second = span.TotalSeconds;

                    size = r.Read(buffer, 0, bufferLength);
                }

                //添加尾部的时间戳
                postStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                postStream.Close();

                //获取服务器端的响应
                WebResponse webRespon = httpReq.GetResponse();
                Stream s = webRespon.GetResponseStream();
                StreamReader sr = new StreamReader(s);

                //读取服务器端返回的消息
                string serverMsg = sr.ReadLine();
                s.Close();
                sr.Close();
            }
            catch (Exception ex)
            {

            }
            finally
            {
                fs.Close();
                r.Close();
            }
        }*/

        static public void FileDownload(int id, string tip, string saveFile, QueryResultDelegate<AsyncCompletedEventArgs> callback)
        {
            Uri uri = new Uri(string.Format("{0}/note/fileDownload.action?id={1}", server, id));
            var wc = new HttpClient(cookie) { Encoding = Encoding.UTF8 };
            ShowProgress(tip, "请等待......");
            wc.DownloadFileAsync(uri, saveFile);
            wc.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs args)
                {
                    _progressDialog.IncrementProgressBy(args.ProgressPercentage);
                };
            wc.DownloadFileCompleted += delegate(object sender, AsyncCompletedEventArgs args)
                {
                    if (context == null)
                        callback(null, args);
                    else
                        context.RunOnUiThread(() =>
                        {
                            HideProgress();
                            callback(null, args);
                        });
                };           
        }
    }
}
